// --------------------------------------------------------------------
    // 网络编程socket封装实现
// --------------------------------------------------------------------


#include "sock.hpp"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


namespace ymbxSock{
ymbxSocket::ymbxSocket(){
    CreateLog("socketlogger");
    CreateLog("udplogger");
    CreateLog("tcplogger");
}
void ymbxSocket::Socket(const std::string &type)
{
    if (type == "tcp")
    {
        _sock = socket(AF_INET, SOCK_STREAM, 0);
    }
    else
    {
        _sock = socket(AF_INET, SOCK_DGRAM, 0);
    }
    if (_sock < 0)
    {
        LOG_FATAL("socketlogger", "创建socket失败：",strerror(errno));
        abort();
    }

}
void ymbxSocket::StrConvertoSock(const std::string& ip,uint16_t port,struct ::sockaddr_in* addr){
    addr->sin_family=AF_INET;
    addr->sin_port=htons(port);
    // iaddr.sin_addr.s_addr=inet_addr(ip.c_str());
    int ret=inet_pton(AF_INET,ip.c_str(),&addr->sin_addr);
    if(ret==0){
        LOG_ERROR("socketlogger","字符串IP地址传入错误\n");
    }else if(ret<0){
        LOG_ERROR("socketlogger","af传入失败：",strerror(errno));
    }
}
void ymbxSocket::SockConvertoStr(std::string* ip,uint16_t* port,struct ::sockaddr_in& addr){
    char buffer[1024];
    *port=ntohs(addr.sin_port);
    auto pstr =inet_ntop(AF_INET,&addr.sin_addr,buffer,INET_ADDRSTRLEN);
    if(pstr==nullptr){
        LOG_ERROR("socketlogger","网络IP地址转换为字符串失败：",strerror(errno));
    }
    *ip+=pstr;
}
void ymbxSocket::Bind(const std::string& ip,uint16_t port){
    struct sockaddr_in addr;
    addr.sin_family=AF_INET;
    addr.sin_port=htons(port);
    // 云服务器绑定INADDR_ANY
    addr.sin_addr.s_addr=INADDR_ANY;
    // addr.sin_addr.s_addr=inet_addr(ip.c_str());
    socklen_t len=sizeof(addr);
    int ret=bind(_sock,(struct sockaddr*)&addr,len);
    if(ret<0){
        LOG_FATAL("socketlogger","绑定ip和port失败：",strerror(errno));
        abort();
    }

}
void ymbxSocket::Listen(int num){
    // listen 第二个参数限制了半连接队列和全连接队列的长度，为num+1。Linux下最大值128
    int ret=listen(_sock,num);
    if(ret<0){
        LOG_FATAL("socketlogger","监听ip和port失败：",strerror(errno));
        abort();
    }
}
void ymbxSocket::Connect(const std::string& ip,uint16_t port){
    struct sockaddr_in addr;
    addr.sin_family=AF_INET;
    addr.sin_port=htons(port);
    addr.sin_addr.s_addr=inet_addr(ip.c_str());
    int ret=connect(_sock,(struct sockaddr*)&addr,sizeof(addr));
    if(ret<0){
        LOG_ERROR("socketlogger","建立连接失败：",strerror(errno));
    }
}
int ymbxSocket::Accept(std::string* ip,uint16_t* port){
    struct sockaddr_in addr;
    socklen_t len=sizeof(addr);
    int ret=accept(_sock,(struct sockaddr*)&addr,&len);
    if(ret<0){
        LOG_ERROR("socketlogger","接收连接失败：",strerror(errno));
        return -1;
    }
    SockConvertoStr(ip,port,addr);
    return ret;
}
void ymbxSocket::Close(){
    close(_sock);
}
void ymbxUdpSocket::Sendto(const std::string&ip,uint16_t port,const std::string& mes){
    struct sockaddr_in addr;
    socklen_t len=sizeof(addr);
    StrConvertoSock(ip,port,&addr);
    int ret=sendto(Getsock(),mes.c_str(),mes.size(),0,(struct sockaddr*)&addr,len);
    if(ret<0){
        LOG_ERROR("udplogger","发送数据失败：",strerror(errno));
    }
}
void ymbxUdpSocket::Recvfrom(std::string* ip,uint16_t* port,std::string* mes){
    char buffer[1024];
    memset(buffer,0,sizeof(buffer));
    struct sockaddr_in addr;
    //必须初始化大小！！！
    socklen_t len=sizeof(addr);
    int ret=recvfrom(Getsock(),buffer,sizeof(buffer)-1,0,(struct sockaddr*)&addr,&len);
    if(ret<0){
        LOG_ERROR("udplogger","接收数据失败：",strerror(errno));
    }
    *mes+=buffer;
    ymbxSocket::SockConvertoStr(ip,port,addr);
}
void ymbxTcpSocket::Send(int sock,const std::string& mes){
    int ret=send(sock,mes.c_str(),mes.size(),0);
    if(ret<0){
        LOG_ERROR("tcplogger","发送数据失败：",strerror(errno));
    }
}
void ymbxTcpSocket::Recv(int sock,std::string* mes){
    char buffer[1024];
    memset(buffer,0,sizeof(buffer));
    int ret=recv(sock,buffer,sizeof(buffer),0);
    if(ret<0){
        LOG_ERROR("tcplogger","接收数据失败：",strerror(errno));
    }else if(ret==0){
        LOG_INFO("tcplogger","连接关闭");
    }
    *mes+=buffer;
}
}